﻿/******************************************************************************
    Copyright (C) 2020 by Zaodao(Dalian) Education Technology Co., Ltd.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/

#include "recorder-app.h"
#include "recorder-define.h"
#include "recorder-platform.h"

#include <libavcodec/avcodec.h>
#include <QDir>
#include <cstdarg>  // 为 va_list 支持
#include <cstdio>   // 为 vsnprintf 支持

#include "obs.h"

#define INPUT_AUDIO_SOURCE  "wasapi_input_capture"
#define OUTPUT_AUDIO_SOURCE "wasapi_output_capture"

// 静态实例指针定义
ZDTalkRecorder* ZDTalkRecorder::s_instance = nullptr;

// OBS日志重定向函数
static void obs_log_handler(int level, const char *msg, va_list args, void *param)
{
    Q_UNUSED(param);
    
    // 使用 vsnprintf 正确格式化日志消息
    char formatted_msg[4096];
    vsnprintf(formatted_msg, sizeof(formatted_msg), msg, args);
    
    switch (level) {
    case LOG_ERROR:
        qCritical() << "[OBS]" << formatted_msg;
        break;
    case LOG_WARNING:
        qWarning() << "[OBS]" << formatted_msg;
        break;
    case LOG_INFO:
        qInfo() << "[OBS]" << formatted_msg;
        break;
    case LOG_DEBUG:
        qDebug() << "[OBS]" << formatted_msg;
        break;
    default:
        qDebug() << "[OBS]" << formatted_msg;
        break;
    }
}

ZDTalkRecorder::ZDTalkRecorder(QObject *parent)
    : QObject(parent)
    , profilerNameStore(nullptr)
{
    qDebug() << "[RECORDER] ZDTalkRecorder constructor starting...";
    
    // 设置静态实例指针
    s_instance = this;
    qDebug() << "[RECORDER] Static instance pointer set";
    
    // 设置OBS日志处理器，统一日志输出
    qDebug() << "[RECORDER] Setting OBS log handler...";
    base_set_log_handler(obs_log_handler, nullptr);
    qDebug() << "[RECORDER] OBS log handler set";
    
#ifdef _WIN32
    qDebug() << "[RECORDER] Disabling audio ducking...";
    DisableAudioDucking(true);
    qDebug() << "[RECORDER] Audio ducking disabled";

    qDebug() << "[RECORDER] Getting Windows version...";
    uint32_t ver = GetWindowsVersion();
    qDebug() << "[RECORDER] Windows version:" << ver;
    if (ver > 0 && ver < 0x602) {
        qInfo("Enable Aero.");
        SetAeroEnabled(true);
    }
#endif

#ifndef TEST
    qDebug() << "[RECORDER] Creating RecorderClient...";
    client_ = new RecorderClient(this);
    qDebug() << "[RECORDER] RecorderClient created";
    
    // 连接退出信号
    qDebug() << "[RECORDER] Connecting RecorderClient exit signal...";
    connect(client_, &RecorderClient::requestExit, this, [this]() {
        qDebug() << "[RECORDER] RecorderClient requested exit";
        // 这里可以处理退出逻辑，比如停止录制等
        // 如果需要退出整个应用程序，可以发送信号给MMService
    });
    qDebug() << "[RECORDER] RecorderClient exit signal connected";
#endif

    qDebug() << "[RECORDER] ZDTalkRecorder constructor completed successfully";
}

ZDTalkRecorder::~ZDTalkRecorder()
{
#ifdef _WIN32
    DisableAudioDucking(false);
#endif

#ifndef TEST
    delete client_;
#endif

    global_config_.Save();
    
    // 清除静态实例指针
    if (s_instance == this) {
        s_instance = nullptr;
    }
}

const char *ZDTalkRecorder::InputAudioSource() const
{
    return INPUT_AUDIO_SOURCE;
}

const char *ZDTalkRecorder::OutputAudioSource() const
{
    return OUTPUT_AUDIO_SOURCE;
}

int ZDTalkRecorder::Init(const QString &server, const QString &config)
{
    if (!InitGlobalConfig(config))
        return NEGATIVE(kErrorClientStartup);

#ifndef TEST
    client_->ConnectToServer(server);
    
    // 应用配置
    ApplyConfig();
#endif

    return kErrorNone;
}

QString ZDTalkRecorder::GetValidBasePath()
{
    QString base_path = QCoreApplication::applicationDirPath();
#ifndef TEST
    // 强制使用 obs 子目录结构
    base_path += "/obs";
#endif
    return base_path;
}

bool ZDTalkRecorder::InitGlobalConfig(const QString &path)
{
    const QString base_path = GetValidBasePath();
    QString config_path     = path;
    if (path.isEmpty())
        config_path = base_path + "/data/config.ini";
    int errorcode = global_config_.Open(config_path.toUtf8().constData(),
        CONFIG_OPEN_ALWAYS);
    if (errorcode != CONFIG_SUCCESS) {
        qWarning("Failed to open %s: %d", config_path.toUtf8().constData(),
            errorcode);
        return false;
    } else
        qInfo() << "Global config path:" << config_path;

    if (config_has_user_value(global_config_, "General", "BasePath")) {
        const char *old_path =
            config_get_string(global_config_, "General", "BasePath");
        if (base_path != old_path) {
            config_set_string(global_config_, "General", "BasePath",
                base_path.toUtf8().constData());
        }
    }

    if (!config_has_user_value(global_config_, "Output", "RecFormat")) {
        config_set_int(global_config_, "Video", "AdapterIdx", 0);
        config_set_int(global_config_, "Video", "OutputCX", 1280);
        config_set_int(global_config_, "Video", "OutputCY", 720);
        config_set_uint(global_config_, "Video", "FPSInt", 15);
        config_set_string(global_config_, "Video", "ScaleType", "bicubic");
        config_set_int(global_config_, "Audio", "SampleRate", 44100);
        config_set_string(global_config_, "Output", "RecFormat", "mp4");
        config_set_string(global_config_, "Output", "StreamEncoder",
            SIMPLE_ENCODER_X264);
        config_set_uint(global_config_, "Output", "VBitrate", 150);
        config_set_uint(global_config_, "Output", "ABitrate", 128);
    }

    config_remove_value(global_config_, "Output", "FilePath");
    config_set_default_string(global_config_, "General", "BasePath",
        base_path.toUtf8().constData());

    InitDefaultsGlobalConfig();

    return true;
}

void ZDTalkRecorder::InitDefaultsGlobalConfig()
{
    if (!global_config_)
        return;

    config_set_default_string(global_config_, "General", "Language", "en-US");

    config_set_default_string(global_config_, "Output", "RecMode", "ffmpeg");

    config_set_default_bool(global_config_, "Output", "Reconnect", false);

    config_set_default_string(global_config_, "Output", "StreamEncoder",
        SIMPLE_ENCODER_X264);
    config_set_default_string(global_config_, "Output", "RecEncoder",
        SIMPLE_ENCODER_X264);

    config_set_default_uint(global_config_, "Output", "VBitrate", 150);
    config_set_default_uint(global_config_, "Output", "ABitrate", 128);
    config_set_default_string(global_config_, "Output", "Preset", "veryfast");

    // Video -------------------------------------------------------------------
    config_set_default_int(global_config_, "Video", "AdapterIdx", 0);
    config_set_default_int(global_config_, "Video", "BaseCX", 1920);
    config_set_default_int(global_config_, "Video", "BaseCY", 1080);
    config_set_default_int(global_config_, "Video", "OutputCX", 1280);
    config_set_default_int(global_config_, "Video", "OutputCY", 720);
    config_set_default_uint(global_config_, "Video", "FPSInt", 15);
    // bilinear:fastest and takes the fewest resources, but doesn't look as good
    // bicubic
    // lanczos:takes more resources but looks better
    config_set_default_string(global_config_, "Video", "ScaleType", "bicubic");
    config_set_default_string(global_config_, "Video", "ColorFormat", "I420");
    config_set_default_string(global_config_, "Video", "ColorSpace", "601");
    config_set_default_string(global_config_, "Video", "ColorRange", "Partial");

    // Audio -------------------------------------------------------------------
    config_set_default_int(global_config_, "Audio", "SampleRate", 44100);
    config_set_default_string(global_config_, "Audio", "ChannelSetup",
        "Stereo");
    config_set_default_double(global_config_, "Audio", "InputGain", 0);
    config_set_default_double(global_config_, "Audio", "OutputGain", 0);
    config_set_default_bool(global_config_, "Audio", "Monitor", false);
    config_set_default_bool(global_config_, "Audio", "InputNoiseSuppress",
        false);
}

void ZDTalkRecorder::ApplyConfig()
{
    qDebug() << "[RECORDER] Applying recorder configuration...";
    
    // 设置日志路径
    if (!m_config.logPath.isEmpty()) {
        qDebug() << "[RECORDER] Setting log path:" << m_config.logPath;
        // 设置日志文件路径到全局配置
        config_set_string(global_config_, "General", "LogPath", m_config.logPath.toUtf8().constData());
    }
    
    // 设置崩溃日志路径
    if (!m_config.crashPath.isEmpty()) {
        qDebug() << "[RECORDER] Setting crash log path:" << m_config.crashPath;
        // 设置崩溃日志路径到全局配置
        config_set_string(global_config_, "General", "CrashLogPath", m_config.crashPath.toUtf8().constData());
    }
    
    // 设置用户信息
    if (!m_config.userName.isEmpty()) {
        qDebug() << "[RECORDER] Setting user name:" << m_config.userName;
        config_set_string(global_config_, "General", "UserName", m_config.userName.toUtf8().constData());
    }
    
    if (!m_config.userId.isEmpty()) {
        qDebug() << "[RECORDER] Setting user ID:" << m_config.userId;
        config_set_string(global_config_, "General", "UserId", m_config.userId.toUtf8().constData());
    }
    
    // 设置录制源类型
    qDebug() << "[RECORDER] Setting recording source type:" << m_config.recordingSourceType;
    config_set_int(global_config_, "Audio", "RecordingSourceType", m_config.recordingSourceType);
    
    // 设置共享内存名称
    if (!m_config.sharedMemoryName.isEmpty()) {
        qDebug() << "[RECORDER] Setting shared memory name:" << m_config.sharedMemoryName;
        config_set_string(global_config_, "Audio", "SharedMemoryName", m_config.sharedMemoryName.toUtf8().constData());
    }
    
    // 根据录制源类型配置音频源
    if (m_config.recordingSourceType == 1) {
        // 共享内存录制模式
        qDebug() << "[RECORDER] Configuring for shared memory recording mode";
        // 配置使用共享内存作为音频源
        config_set_string(global_config_, "Audio", "InputSource", "shared_memory_input");
        config_set_string(global_config_, "Audio", "OutputSource", "shared_memory_output");
    } else {
        // 设备录制模式
        qDebug() << "[RECORDER] Configuring for device recording mode";
        // 使用默认的设备音频源
        config_set_string(global_config_, "Audio", "InputSource", INPUT_AUDIO_SOURCE);
        config_set_string(global_config_, "Audio", "OutputSource", OUTPUT_AUDIO_SOURCE);
    }
    
    // 保存配置
    global_config_.Save();
    
    qDebug() << "[RECORDER] Recorder configuration applied successfully";
}